/******************************************************************************
 * This header contains class definitions for classes used in module          *
 * REMEZ.CPP. Also inline functions from these classes are included here.     *
 ******************************************************************************/

#ifndef __FOBJECTS_H
#define __FOBJECTS_H

#ifndef __cplusplus
#error This module requires C++
#endif

#include <assert.h>             /* for debugging purposes */

#ifdef NDEBUG
#define fail(p)   ((void)0)     /* for debugging purposes */
#else
#ifdef __GNUC__
#define fail(p)   ((void) __assert(#p, __FILE__, __LINE__ ))
#else
#define fail(p)   ((void) __assertfail("Failed: %s, file %s, line %d\n", \
                  #p, __FILE__, __LINE__ ))
#endif // __GNUC__
#endif

#if !defined(__BORLANDC__) || __BORLANDC__ > 0x200
#define DELETE_ARRAY(array, size) delete [] array
#else
#define DELETE_ARRAY(array, size) delete [size] array
#endif

typedef double Float;           /* our default floating point type */

enum SearchTypes                /* search types used to find new extremals */
{
  ExhaustiveOnly,
  UseSelective,
  UseSelectCubic
};

enum FilterTypes                /* filter types we may design */
{
  OddSymetrical,
  OddAntysymetrical,
  EvenSymetrical,
  EvenAntysymetrical,
  OddDifferentiator
};

/******************************************************************************
 * Class BandInfo holds information about:                                    *
 *   band low edge                                                            *
 *   band high edge                                                           *
 *   transmitation inside band                                                *
 *   error ratio inside band                                                  *
 * It also allows reading and setting values listed above                     *
 * I hope function names are selfexplanatory                                  *
 ******************************************************************************/

class BandInfo
{
  protected:
    Float LowEdge, HighEdge;
    Float ErrorRatio;
    Float Trans;
  public:
    BandInfo(Float _LowEdge, Float _HighEdge, Float _Error, Float _Trans);
    BandInfo(void);
    Float GetLow(void) const;
    Float GetHigh(void) const;
    Float GetErrorRatio(void) const;
    Float GetTrans(void) const;
    void SetLow(Float Val);
    void SetHigh(Float Val);
    void SetErrorRatio(Float Val);
    void SetTrans(Float Val);
};

/******************************************************************************
 * Here we are some short functions from BandInfo class which are made inline *
 ******************************************************************************/

inline BandInfo::BandInfo(Float _LowEdge, Float _HighEdge, Float _Error, Float _Trans) :
       LowEdge(_LowEdge), HighEdge(_HighEdge), ErrorRatio(_Error), Trans(_Trans)
{
}

inline BandInfo::BandInfo(void) :
       LowEdge(0), HighEdge(0), ErrorRatio(0), Trans(0)
{
}

inline Float BandInfo::GetLow(void) const
{
  return (LowEdge);
}

inline Float BandInfo::GetHigh(void) const
{
  return (HighEdge);
}

inline Float BandInfo::GetErrorRatio(void) const
{
  return (ErrorRatio);
}

inline Float BandInfo::GetTrans(void) const
{
  return (Trans);
}

inline void BandInfo::SetLow(Float Val)
{
  LowEdge = Val;
}

inline void BandInfo::SetHigh(Float Val)
{
  HighEdge = Val;
}

inline void BandInfo::SetErrorRatio(Float Val)
{
  ErrorRatio = Val;
}

inline void BandInfo::SetTrans(Float Val)
{
  Trans = Val;
}

/******************************************************************************
 * Class Filter holds information about filter passbands and stopbands.       *
 ******************************************************************************/

class Filter
{
  protected:
    BandInfo *Bands;
    int NoBands;
  public:
    Filter(void);
    Filter(int _NoBands);
    Filter(const Filter &Src);
    ~Filter(void);
    BandInfo &operator[](int BandNo);
    const BandInfo &operator[](int BandNo) const;
    const Filter &operator=(const Filter &Src);
    void SetBand(int BandNo, const BandInfo &Band);
    void SetNoBands(int _NoBands);
    friend int GetBandsNo(const Filter &F);
};

/******************************************************************************
 * Inline functions from class Filter are below                               *
 ******************************************************************************/

inline Filter::Filter(void) : Bands(0), NoBands(0)
{
}

inline Filter::Filter(int _NoBands)
{
  Bands = new BandInfo[NoBands = _NoBands];
}

inline Filter::Filter(const Filter &Src) : Bands(0)
{
  *this = Src;
}

inline Filter::~Filter(void)
{
  if(Bands)
    DELETE_ARRAY(Bands, NoBands);
}

inline BandInfo &Filter::operator[](int BandNo)
{
{
  assert(BandNo >= 1 && BandNo <= NoBands);
  return (Bands[BandNo - 1]);
}
}

inline const BandInfo &Filter::operator[](int BandNo) const
{
{
  assert(BandNo >= 1 && BandNo <= NoBands);
  return (Bands[BandNo - 1]);
}
}

inline int GetBandsNo(const Filter &F)
{
  return (F.NoBands);
}

inline void Filter::SetBand(int BandNo, const BandInfo &Band)
{
  assert(BandNo >= 1 && BandNo <= NoBands);
  Bands[BandNo - 1] = Band;
}

inline void Filter::SetNoBands(int _NoBands)
{
  assert(_NoBands >= 1);
  if(_NoBands != NoBands)
  {
    DELETE_ARRAY(Bands, NoBands);
    Bands = new BandInfo[NoBands = _NoBands];
  }
}

/******************************************************************************
 * Class Vector represents one dimensional dynamic array with ability to set  *
 * lower and upper index limit. It provides methods for setting and getting   *
 * limits, copying, outputing, and checking if given value is inside array    *
 ******************************************************************************/
class Vector
{
  protected:
    Float *tbl;
    int Lo, Hi;
  public:
    Vector(void);
    Vector(int _Lo, int _Hi);
    Vector(const Vector &Src);
    ~Vector(void);
    Float &operator[](int i);
    Float operator[](int i) const;
    const Vector &operator=(const Vector &Src);
    void SetDims(int _Lo, int _Hi);
    friend int Lo(const Vector &V);
    friend int Hi(const Vector &V);
    friend int In(const Vector &V, Float x);
};

inline Vector::Vector(void) : tbl(0), Lo(0), Hi(-1)
{
}

inline Vector::Vector(int _Lo, int _Hi)
{
  tbl = new Float[(Hi = _Hi) - (Lo = _Lo) + 1];
}

inline Vector::Vector(const Vector &Src) : tbl (0)
{
  *this = Src;
}

inline Vector::~Vector(void)
{
  if(tbl)
    DELETE_ARRAY(tbl, Hi - Lo + 1);
}

inline Float &Vector::operator[](int i)
{
  assert(i >= Lo && i <= Hi);
  return (tbl[i - Lo]);
}

inline Float Vector::operator[](int i) const
{
  assert(i >= Lo && i <= Hi);
  return (tbl[i - Lo]);
}

inline int Lo(const Vector &V)
{
  return (V.Lo);
}

inline int Hi(const Vector &V)
{
  return (V.Hi);
}

/******************************************************************************
 * Class Array is a vector of objects of class Vector - it is similar to two  *
 * dimensional array with exception, that each vector can have its own size   *
 * and limits. Class provides methods similar to that found in class Vector   *
 ******************************************************************************/
class Array
{
  protected:
    Vector *tbl;
    int Lo, Hi;
  public:
    Array(void);
    Array(int _Lo, int _Hi);
    Array(const Array &Src);
    ~Array(void);
    Vector &operator[](int i);
    const Vector &operator[](int i) const;
    const Array &operator=(const Array &Src);
    void SetDims(int _Lo, int _Hi);
    friend int Lo(const Array &A);
    friend int Hi(const Array &A);
    friend int In(const Array &A, Float x);
};

inline Array::Array(void) : tbl(0), Lo(0), Hi(-1)
{
}

inline Array::Array(int _Lo, int _Hi)
{
  tbl = new Vector[(Hi = _Hi) - (Lo = _Lo) + 1];
}

inline Array::Array(const Array &Src) : tbl (0)
{
  *this = Src;
}

inline Array::~Array(void)
{
  if(tbl)
    DELETE_ARRAY(tbl, Hi - Lo + 1);
}

inline Vector &Array::operator[](int i)
{
  assert(i >= Lo && i <= Hi);
  return (tbl[i - Lo]);
}

inline const Vector &Array::operator[](int i) const
{
  assert(i >= Lo && i <= Hi);
  return (tbl[i - Lo]);
}

inline int Lo(const Array &A)
{
  return (A.Lo);
}

inline int Hi(const Array &A)
{
  return (A.Hi);
}

/******************************************************************************
 * Class List - double linked list of Float values. Try to understand it by   *
 * yourself!                                                                  *
 ******************************************************************************/
struct Node
{
  Node(Float _Val);
  Float Val;
  Node *Prev, *Next;
};

class List
{
  private:
    List(const List &L);
    void operator=(const List &L);
    void RemoveList(void);
    Node *First, *Last, *Curr;
  public:
    List(void);
    ~List(void);
    void Add(Float Val);
    void InsertAfter(Float Val);
    void InsertBefore(Float Val);
    void SetFirst(void);
    void SetLast(void);
    void Reset(void);
    void *operator++(void);
    void *operator--(void);
    operator Float(void);
    void operator!(void);
    Float operator+(void);
    Float operator-(void);
    friend int In(const List &L, Float Val);
};

inline Node::Node(Float _Val) : Val(_Val), Prev(0), Next(0)
{
}

inline List::List(void) : First(0), Last(0), Curr(0)
{
}

inline List::~List(void)
{
  RemoveList();
}

inline void List::SetFirst(void)
{
  Curr = First;
}

inline void List::SetLast(void)
{
  Curr = Last;
}

inline void List::Reset(void)
{
  Curr = 0;
}

inline void *List::operator++(void)
{
  if(Curr)
    Curr = Curr->Next;
  return (Curr);
}

inline void *List::operator--(void)
{
  if(Curr)
    Curr = Curr->Prev;
  return (Curr);
}

inline List::operator Float(void)
{
  assert(Curr);
  return (Curr->Val);
}

inline void List::operator!(void)
{
  RemoveList();
}

inline Float List::operator+(void)
{
  assert(Curr && Curr->Next);
  return (Curr->Next->Val);
}

inline Float List::operator-(void)
{
  assert(Curr && Curr->Prev);
  return (Curr->Prev->Val);
}

inline Float sgn(Float x)
{
  return (x >= 0 ? 1.0 : -1.0);
}

inline Float sqr(Float x)
{
  return (x * x);
}

/******************************************************************************
 * Calculates cosinus for each element in Src and return an array filled with *
 * these values                                                               *
 ******************************************************************************/
Array cos(const Array &Src);

/******************************************************************************
 * Floating point comparison                                                  *
 ******************************************************************************/
int Eq(long double x1, long double x2);

/* reset to defaults for turned off warnings */

#endif /* __FOBJECTS_H */
